/*
 * FirstDivide.cpp
 *
 *  Created on: 13/02/2014
 *      Author: root
 */

#include "FirstBranch.h"
#include "DppmParams.h"
#include "SortedBuffer.h"
#include "Tuple.h"
#include <iostream>
#include <stdlib.h>

using namespace std;


extern DppmParams * dppm;
extern SortedBuffer * tuples;
extern int rank, size;

Tuple * MakeTupleFromModes(int * startTuple,int numAct,int now){


	int  array[Tuple::tuplesIntSize];
	memset(array,0,sizeof(int) * Tuple::tuplesIntSize);
	array[0] = now;
	memcpy(&(array[3 + numAct]),startTuple,sizeof(int)* numAct);
	Tuple * t = new Tuple(Tuple::tuplesIntSize,array);

//	if (!rank){
//			for(int i = 0; i < Tuple::tuplesIntSize; i++)
//				cout<<"array["<<i<<"]: "<<array[i]<<endl;
//	}

	int numPreds = 0;
	int * preds = NULL;
	int maxTimePreds;
	int * times = NULL;
	for(int i = 0; i <= now; i++){
		maxTimePreds = 0;
		numPreds = dppm->getActivityNumPreds(i);
		preds = dppm->getActivityPreds(i);
		times = dppm->getActivityModesTimes(i);

		for(int j = 0; j < numPreds; j++){

			if(maxTimePreds < t->times(preds[j]) ){
				maxTimePreds = t->times(preds[j]);
			}
		}

		t->times(i,maxTimePreds + times[t->modes(i)] );

		if( t->time() < t->times(i) ){
			t->time(t->times(i));
		}

		t->cost( t->cost() + dppm->getActivityModesCosts(i)[t->modes(i)] );

	}

	return t;
}


int FirstBranch(){

	if (rank == 0) cout<<"FirstBranch: "<<62<<endl;
	int numAct = dppm->getNumActivities();
	int maxIndFB = 0;
	int numModes[numAct];
	int numTuples = 1;
	int * c = (int*)malloc(sizeof(int)*numAct);

	c[0] = 1;
	numModes[0] = dppm->getActivityNumModes(0);
	numTuples *= numModes[0];

	for(int i = 1; ( i < numAct )&&( numTuples < size ) ; i++){

		numModes[i] = dppm->getActivityNumModes(i);
		numTuples *= numModes[i];
		maxIndFB++;
		c[i] = c[i - 1] * numModes[i];
	}

	if (rank == 0) cout<<"FirstBranch: "<<76<<endl;

	//c = (int*)realloc(c,sizeof(int)*(maxIndFB+1)); //si reduce el tamaño del array no cambia el puntero de lugar???

	int div = numTuples / size ;
	int mod = numTuples % size ;

	int indexTuple = 0;
	int myTuples = rank < mod ? div + 1 : div;

	indexTuple = rank < mod ? ((div + 1) * rank ) : ((div + 1) * mod   +  div * (rank - mod));

	int startTuple[numAct];
	int aux = indexTuple + 1;
	memset(startTuple,0,sizeof(int)*numAct);

	if (rank == 0) cout<<"FirstBranch: "<<93<<endl;
	if (rank == 0) cout<<"maxIndFB :"<<maxIndFB<<"numAct: "<<numAct<<endl;

	for(int j = 0 ; j <= maxIndFB ; j++){

		startTuple[j] = (aux / c[maxIndFB - j]) - 1;
		aux = aux % c[maxIndFB - j];

	}

	if (rank == 0) cout<<"FirstBranch: "<<100<<endl;



	Tuple * t = MakeTupleFromModes(startTuple,numAct,maxIndFB);
	tuples->push(t);
	//if(rank) t->print();
	int carry = 0;

	if (rank == 0) cout<<"FirstBranch: "<<106<<endl;

	for(int i = 1; i < myTuples; i++){

		carry = 1;
		for(int j = 0; (carry == 1 && j <= maxIndFB); j++){

			startTuple[j] = startTuple[j] + 1;
			carry =  startTuple[j] / numModes[j];
			startTuple[j] %= numModes[j];

		}

		t = MakeTupleFromModes(startTuple,numAct,maxIndFB);
		tuples->push(t);
		//if(rank) t->print();
	}

	cout<<"rank: "<<rank<<" tuples->size() =  "<<tuples->size()<<endl;
	return 0;
}
